// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: GPL-3.0-only

package badger_dao_impl

import (
	"context"
	"path/filepath"
	"strings"

	"gitcode.com/openseaotter/so_proto_gen_go.git/member_api"
	"gitcode.com/openseaotter/so_server/storage/core"
	"gitcode.com/openseaotter/so_server/utils"
	"github.com/dgraph-io/badger/v4"
	"google.golang.org/protobuf/proto"
)

type _MemberDao struct {
	dbh *badger.DB
}

func NewMemberDao() (core.MemberDao, error) {
	dbPath := filepath.Join(utils.DATA_DIR_PATH, "member")
	options := badger.DefaultOptions(dbPath)
	dbh, err := badger.Open(options)
	if err != nil {
		return nil, err
	}
	return &_MemberDao{dbh: dbh}, nil
}

func (db *_MemberDao) genKey(projectId, memberUserId string) string {
	return strings.Join([]string{projectId, memberUserId}, "\t")
}

func (db *_MemberDao) genKeyPrefix(projectId string) string {
	return projectId + "\t"
}

func (db *_MemberDao) Set(ctx context.Context, projectId string, memberInfo *member_api.MemberInfo) error {
	value, err := proto.Marshal(memberInfo)
	if err != nil {
		return err
	}
	key := db.genKey(projectId, memberInfo.MemberUserId)

	txn := db.dbh.NewTransaction(true)
	defer txn.Discard()

	err = txn.Set([]byte(key), value)
	if err != nil {
		return err
	}
	return txn.Commit()
}

func (db *_MemberDao) Get(ctx context.Context, projectId, memberUserId string) (*member_api.MemberInfo, error) {
	txn := db.dbh.NewTransaction(false)
	defer txn.Discard()

	key := db.genKey(projectId, memberUserId)

	item, err := txn.Get([]byte(key))
	if err != nil {
		return nil, err
	}
	if item.IsDeletedOrExpired() {
		return nil, badger.ErrKeyNotFound
	}
	value, err := item.ValueCopy(nil)
	if err != nil {
		return nil, err
	}
	memberInfo := &member_api.MemberInfo{}
	err = proto.Unmarshal(value, memberInfo)
	if err != nil {
		return nil, err
	}
	return memberInfo, nil
}

func (db *_MemberDao) Remove(ctx context.Context, projectId, memberUserId string) error {
	txn := db.dbh.NewTransaction(true)
	defer txn.Discard()

	key := db.genKey(projectId, memberUserId)
	err := txn.Delete([]byte(key))
	if err != nil {
		return err
	}
	return txn.Commit()
}

func (db *_MemberDao) List(ctx context.Context, projectId string) ([]*member_api.MemberInfo, error) {
	txn := db.dbh.NewTransaction(false)
	defer txn.Discard()

	keyPrefix := db.genKeyPrefix(projectId)
	option := badger.IteratorOptions{
		PrefetchValues: true,
		PrefetchSize:   100,
		Reverse:        false,
		AllVersions:    false,
		Prefix:         []byte(keyPrefix),
	}
	iter := txn.NewIterator(option)
	defer iter.Close()

	memberInfoList := []*member_api.MemberInfo{}
	for iter.Rewind(); iter.Valid(); iter.Next() {
		item := iter.Item()
		if item.IsDeletedOrExpired() {
			continue
		}
		value, err := item.ValueCopy(nil)
		if err != nil {
			return nil, err
		}
		memberInfo := &member_api.MemberInfo{}
		err = proto.Unmarshal(value, memberInfo)
		if err != nil {
			return nil, err
		}
		memberInfoList = append(memberInfoList, memberInfo)
	}
	return memberInfoList, nil
}
